{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "#----------------------------------拟合圆，得到圆心和半径------------------------------------------#\n",
    "from numpy import *;#导入numpy的库函数\n",
    "import numpy as np; #这个方式使用numpy的函数时，需要以np.开头。\n",
    "\n",
    "def circleLeastFit(points):\n",
    "    center_x = 0.0\n",
    "    center_y = 0.0\n",
    "    radius = 0.0\n",
    "\n",
    "    sum_x = sum_y = 0.0\n",
    "    sum_x2 = sum_y2 = 0.0\n",
    "    sum_x3 = sum_y3 = 0.0\n",
    "    sum_xy = sum_x1y2 = sum_x2y1 = 0.0\n",
    "    N = len(points)\n",
    "    for i in range(1,N):\n",
    "        x = points[i][0]\n",
    "        y = points[i][1]\n",
    "        x2 = x * x\n",
    "        y2 = y * y\n",
    "        sum_x += x\n",
    "        sum_y += y\n",
    "        sum_x2 += x2\n",
    "        sum_y2 += y2\n",
    "        sum_x3 += x2 * x\n",
    "        sum_y3 += y2 * y\n",
    "        sum_xy += x * y\n",
    "        sum_x1y2 += x * y2\n",
    "        sum_x2y1 += x2 * y\n",
    "\n",
    "    C = D = E = G = H =0.0\n",
    "    a = b = c = 0.0\n",
    "    C = N * sum_x2 - sum_x * sum_x\n",
    "    D = N * sum_xy - sum_x * sum_y\n",
    "    E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x\n",
    "    G = N * sum_y2 - sum_y * sum_y\n",
    "    H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y\n",
    "    a = (H * D - E * G) / (C * G - D * D)\n",
    "    b = (H * C - E * D) / (D * D - G * C)\n",
    "    c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N\n",
    "    \n",
    "    center_x = a / (-2)\n",
    "    center_y = b / (-2)\n",
    "    radius = sqrt(a * a + b * b - 4 * c) / 2\n",
    "    \n",
    "    return center_x, center_y, round(radius,2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "#----------------------------------分析图片，得到响应json--------------------------------------#\n",
    "# -*- coding: utf-8 -*-\n",
    "import urllib.request\n",
    "import urllib.error\n",
    "import time\n",
    "import json\n",
    "\n",
    "def faceIdentify(img_src):\n",
    "    http_url = 'https://api-cn.faceplusplus.com/facepp/v3/detect'\n",
    "    key = \"enFC8NNZcf19CNRZGhGMvGKPHtMgVkfB\"\n",
    "    secret = \"kIV15LIXTSX0gKflGEYHXekj8-mgEuHE\"\n",
    "    # filepath = r\"gg.jpg\"\n",
    "    filepath=img_src\n",
    "\n",
    "    boundary = '----------%s' % hex(int(time.time() * 1000))\n",
    "    data = []\n",
    "    data.append('--%s' % boundary)\n",
    "    data.append('Content-Disposition: form-data; name=\"%s\"\\r\\n' % 'api_key')\n",
    "    data.append(key)\n",
    "\n",
    "    data.append('--%s' % boundary)\n",
    "    data.append('Content-Disposition: form-data; name=\"%s\"\\r\\n' % 'api_secret')\n",
    "    data.append(secret)\n",
    "\n",
    "    data.append('--%s' % boundary)\n",
    "    fr = open(filepath, 'rb')\n",
    "    data.append('Content-Disposition: form-data; name=\"%s\"; filename=\" \"' % 'image_file')\n",
    "    data.append('Content-Type: %s\\r\\n' % 'application/octet-stream')\n",
    "    data.append(fr.read())\n",
    "    fr.close()\n",
    "    data.append('--%s' % boundary)\n",
    "    data.append('Content-Disposition: form-data; name=\"%s\"\\r\\n' % 'return_landmark')\n",
    "    data.append('2')\n",
    "    data.append('--%s' % boundary)\n",
    "    data.append('Content-Disposition: form-data; name=\"%s\"\\r\\n' % 'return_attributes')\n",
    "    data.append(\n",
    "        \"gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus\")\n",
    "    data.append('--%s--\\r\\n' % boundary)\n",
    "\n",
    "    for i, d in enumerate(data):\n",
    "        if isinstance(d, str):\n",
    "            data[i] = d.encode('utf-8')\n",
    "\n",
    "    http_body = b'\\r\\n'.join(data)\n",
    "\n",
    "    # build http request\n",
    "    req = urllib.request.Request(url=http_url, data=http_body)\n",
    "\n",
    "    # header\n",
    "    req.add_header('Content-Type', 'multipart/form-data; boundary=%s' % boundary)\n",
    "\n",
    "    try:\n",
    "        # post data to server\n",
    "        resp = urllib.request.urlopen(req, timeout=5)\n",
    "        # get response\n",
    "        qrcont = resp.read()\n",
    "        # if you want to load as json, you should decode first,\n",
    "        # for example: json.loads(qrcont.decode('utf-8'))\n",
    "        text=json.loads(qrcont.decode('utf-8'))\n",
    "        tt=text.get('faces')[0].get('landmark')\n",
    "        return tt\n",
    "    except urllib.error.HTTPError as e:\n",
    "        print(e.read().decode('utf-8'))\n",
    "        return 'wrong'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "#---------------------------------------特征点分析----------------------------------------------#\n",
    "import math\n",
    "def qradium(a,b,t):\n",
    "    list1=[]\n",
    "    for i in range(a,b):\n",
    "        tt=t.get('contour_left'+str(i))\n",
    "        list1.append([tt.get('x'),tt.get('y')])\n",
    "    x, y, r = circleLeastFit(list1)\n",
    "    return r\n",
    "\n",
    "def chinhu(t):\n",
    "    list2=[]\n",
    "    for i in range(14,17):\n",
    "        text2=t.get('contour_left'+str(i))\n",
    "        list2.append([text2.get('x'),text2.get('y')])\n",
    "        text3=t.get('contour_right'+str(i))\n",
    "        list2.append([text3.get('x'),text3.get('y')])\n",
    "    text4=t.get('contour_chin')\n",
    "    list2.append([text4.get('x'),text4.get('y')])\n",
    "    x, y, r = circleLeastFit(list2);\n",
    "    return r\n",
    "\n",
    "#-----------------------------调用这个方法得到七个特征---------------------------------#\n",
    "def handle_features(text1):\n",
    "    w1=round(math.sqrt((text1.get('contour_right1').get('x')-text1.get('contour_left1').get('x'))**2+(text1.get('contour_right1').get('y')-text1.get('contour_left1').get('y'))**2),2)\n",
    "    w2=round(math.sqrt((text1.get('contour_right3').get('x')-text1.get('contour_left3').get('x'))**2+(text1.get('contour_right3').get('y')-text1.get('contour_left3').get('y'))**2),2)\n",
    "    w3=round(math.sqrt((text1.get('contour_right9').get('x')-text1.get('contour_left9').get('x'))**2+(text1.get('contour_right9').get('y')-text1.get('contour_left9').get('y'))**2),2)\n",
    "    h=round(math.sqrt((text1.get('contour_chin').get('x')-text1.get('nose_bridge1').get('x'))**2+(text1.get('contour_chin').get('y')-text1.get('nose_bridge1').get('y'))**2),2)\n",
    "    r1=qradium(1,7,text1)        \n",
    "    r2=qradium(7,14,text1)\n",
    "    r3=chinhu(text1)\n",
    "    \n",
    "    return w1/h,w2/h,w3/h,h/h,r1/h,r2/h,r3/h\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "import csv\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import operator as op\n",
    "#---------------------------------计算图片特征--------------------------------#\n",
    "\n",
    "def get_imgs_features():\n",
    "    csv_in = pd.read_csv('../labels/output_2.csv', sep = ',', header = None)\n",
    "    csv_in = csv_in.values\n",
    "    img_name = csv_in[:, 1]\n",
    "    img_labl = csv_in[:, 7]\n",
    "    print(img_name.shape[0])\n",
    "    \n",
    "    csv_out = open('features.csv', 'w', newline = '')\n",
    "    csv_write = csv.writer(csv_out, dialect = 'excel')\n",
    "    head = ['id', 'name', 'label', 'w1/h', 'w2/h','w3/h','h/h','r1/h','r2/h','r3/h']\n",
    "    csv_write.writerow(head)\n",
    "\n",
    "    csv_out = open('features.csv', 'a', newline = '')\n",
    "    csv_write = csv.writer(csv_out, dialect = 'excel')\n",
    "\n",
    "    for i in range(1, img_name.shape[0]):\n",
    "\n",
    "        img_src = '../images/' + img_name[i][0:3] + '/' + img_name[i]\n",
    "        w1,w2,w3,h,r1,r2,r3 = handle_features(faceIdentify(img_src))\n",
    "\n",
    "        eachrow = [i, img_name[i], img_labl[i], w1,w2,w3,h,r1,r2,r3]\n",
    "        csv_write.writerow(eachrow)\n",
    "    csv_out.close()\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "296\n"
     ]
    }
   ],
   "source": [
    "#----------------------------------初始化 --------------------------------------#\n",
    "# 预处理图片特征\n",
    "get_imgs_features()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "#--------------------------------------KNN----------------------------------------------#\n",
    "def classify0(inX,dataSet,labels,k):\n",
    "    dataSetSize = dataSet.shape[0]\n",
    "    diffMat = np.tile(inX,(dataSetSize,1))-dataSet\n",
    "    sqDiffMat = diffMat**2\n",
    "    sqDistances = sqDiffMat.sum(axis=1)\n",
    "    distances = sqDistances**0.5\n",
    "    sortedDistIndicies =distances.argsort()\n",
    "    classCount={}\n",
    "    for i in range(k):\n",
    "        voteIlabel = labels[sortedDistIndicies[i]]\n",
    "        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1\n",
    "    sortedClassCount = sorted(classCount.items(),key = operator.itemgetter(1),reverse=True)\n",
    "    return sortedClassCount[0][0]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(296, 10)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.cross_validation import train_test_split\n",
    "import numpy as np\n",
    "import string\n",
    "import operator\n",
    "import pandas as pd\n",
    "\n",
    "d=pd.read_csv('features.csv', sep=',',header=None,encoding='gbk')\n",
    "d=d.values\n",
    "print(d.shape)\n",
    "\n",
    "data=np.vstack((d[1:,3],d[1:,4],d[1:,5],d[1:,6],d[1:,7],d[1:,8],d[1:,9])).T\n",
    "target=d[1:,2]\n",
    "\n",
    "\n",
    "for i in range(data.shape[0]):\n",
    "    for j in range(data.shape[1]):\n",
    "        data[i][j]=float(data[i][j])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "方脸 圆脸\n",
      "方脸 梨形脸\n",
      "方脸 方脸\n",
      "椭圆脸 方脸\n",
      "方脸 圆脸\n",
      "方脸 圆脸\n",
      "方脸 菱形脸\n",
      "圆脸 圆脸\n",
      "椭圆脸 圆脸\n",
      "梨形脸 圆脸\n",
      "圆脸 方脸\n",
      "方脸 方脸\n",
      "方脸 椭圆脸\n",
      "方脸 圆脸\n",
      "椭圆脸 方脸\n",
      "圆脸 圆脸\n",
      "梨形脸 梨形脸\n",
      "方脸 方脸\n",
      "菱形脸 方脸\n",
      "菱形脸 长脸\n",
      "圆脸 方脸\n",
      "方脸 圆脸\n",
      "方脸 圆脸\n",
      "方脸 方脸\n",
      "方脸 圆脸\n",
      "方脸 方脸\n",
      "方脸 菱形脸\n",
      "0.2962962962962963\n"
     ]
    }
   ],
   "source": [
    "\n",
    "X_train,X_test,y_train,y_test=train_test_split(data,target,test_size=0.09,random_state=3)\n",
    "y_predict=np.ones(y_test.shape).tolist()\n",
    "\n",
    "for i in range(y_test.shape[0]):\n",
    "    y_predict[i]=str(y_predict[i])\n",
    "\n",
    "y_predict=np.array(y_predict)\n",
    "\n",
    "mcount=0\n",
    "for i in range(X_test.shape[0]):\n",
    "    y_predict[i]=classify0(X_test[i],X_train,y_train,5)\n",
    "    if(y_test[i].find(y_predict[i])==-1):\n",
    "        mcount+=1\n",
    "    print(y_predict[i],y_test[i])\n",
    "print(1-mcount/y_predict.shape[0])\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
